package com.docparser.processor;

import java.io.FileInputStream;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import com.docparser.util.XmlUtils;

/**
 * 处理DOCX文档以提取数学公式。
 * 负责读取DOCX文件并提取Office Open XML数学元素。
 */
public class DocxProcessor {
    private final String filePath;
    private final DocumentBuilder documentBuilder;

    public DocxProcessor(String filePath) throws Exception {
        this.filePath = filePath;
        this.documentBuilder = XmlUtils.createDocumentBuilder();
    }

    /**
     * 处理DOCX文档并提取数学公式。
     * 对于每个找到的公式，都会调用提供的处理器进行处理。
     *
     * @param handler 用于处理每个找到的公式的回调接口
     * @throws Exception 如果在文档处理过程中发生错误
     */
    public void process(FormulaHandler handler) throws Exception {
        try (FileInputStream fis = new FileInputStream(filePath);
             XWPFDocument document = new XWPFDocument(fis)) {
            
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                String mathXml = "<?xml version='1.0' encoding='UTF-8'?>"
                    + "<root xmlns:m='http://schemas.openxmlformats.org/officeDocument/2006/math'>"
                    + paragraph.getCTP().xmlText()
                    + "</root>";
                if (mathXml.contains("m:oMath")) {
                    System.out.println("\n==== 正在分析段落 ====");
                    System.out.println("原始XML: " + mathXml);
                    
                    processMathParagraph(mathXml, handler);
                }
            }
        }
    }

    /**
     * 处理包含数学内容的段落。
     * 将Office Open XML数学元素转换为LaTeX格式。
     *
     * @param mathXml 包含数学元素的段落的XML内容
     * @param handler 用于处理处理后公式的回调处理器
     * @throws Exception 如果在XML解析或公式处理过程中发生错误
     */
    private void processMathParagraph(String mathXml, FormulaHandler handler) throws Exception {
        Document doc = documentBuilder.parse(new InputSource(new StringReader(mathXml)));
        NodeList mathNodes = doc.getElementsByTagNameNS(
            "http://schemas.openxmlformats.org/officeDocument/2006/math",
            "oMath");
        
        if (mathNodes.getLength() > 0) {
            StringBuilder formula = new StringBuilder();
            MathFormulaProcessor.processOMath((org.w3c.dom.Element) mathNodes.item(0), formula);
            
            String cleanFormula = MathFormulaProcessor.cleanFormula(formula.toString());
            System.out.println("提取的LaTeX公式: " + cleanFormula);
            
            if (!cleanFormula.isEmpty()) {
                handler.handleFormula(cleanFormula);
            }
        }
    }

    /**
     * 用于处理提取公式的函数式接口。
     * 实现可以定义如何处理每个提取的公式。
     */
    @FunctionalInterface
    public interface FormulaHandler {
        /**
         * 对每个在文档中找到的公式调用。
         *
         * @param formula 提取的公式的LaTeX表示
         * @throws Exception 如果在公式处理过程中发生错误
         */
        void handleFormula(String formula) throws Exception;
    }
}
